package com.zhentao.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 验证码服务 - 使用内存存储
 */
@Slf4j
@Service
public class VerificationCodeService {
    
    @Autowired
    private SmsService smsService;
    
    @Value("${sms.code.length:6}")
    private int codeLength;
    
    @Value("${sms.code.expire-time:300}")
    private int expireTime;
    
    @Value("${sms.code.send-interval:60}")
    private int sendInterval;
    
    // 内存存储验证码信息
    private final ConcurrentHashMap<String, VerificationCodeInfo> codeStorage = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, Long> sendTimeStorage = new ConcurrentHashMap<>();
    
    // 定时清理过期数据
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    
    public VerificationCodeService() {
        // 每30秒清理一次过期数据
        scheduler.scheduleAtFixedRate(this::cleanExpiredData, 30, 30, TimeUnit.SECONDS);
    }
    
    // 验证码信息类
    private static class VerificationCodeInfo {
        private final String content;
        private final long createTime;
        
        public VerificationCodeInfo(String content) {
            this.content = content;
            this.createTime = System.currentTimeMillis();
        }
        
        public String getContent() {
            return content;
        }
        
        public long getCreateTime() {
            return createTime;
        }
        
        public boolean isExpired(int expireTimeSeconds) {
            return System.currentTimeMillis() - createTime > expireTimeSeconds * 1000L;
        }
    }
    
    /**
     * 生成随机验证码
     */
    private String generateCode() {
        // 生产模式：生成随机验证码
        java.util.Random random = new java.util.Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < codeLength; i++) {
            code.append(random.nextInt(10));
        }
        return code.toString();
    }
    
    /**
     * 从短信内容中提取验证码
     * @param content 短信内容
     * @return 验证码
     */
    private String extractCodeFromContent(String content) {
        // 从短信内容中提取验证码，格式：【签名】您的验证码是123456，该验证码5分钟内有效
        try {
            String[] parts = content.split("验证码是");
            if (parts.length > 1) {
                String codePart = parts[1].split("，")[0];
                return codePart.trim();
            }
        } catch (Exception e) {
            log.error("提取验证码失败: {}", e.getMessage());
        }
        return null;
    }
    
    /**
     * 清理过期数据
     */
    private void cleanExpiredData() {
        try {
            // 清理过期的验证码
            codeStorage.entrySet().removeIf(entry -> 
                entry.getValue().isExpired(expireTime));
            
            // 清理过期的发送时间记录
            long currentTime = System.currentTimeMillis();
            sendTimeStorage.entrySet().removeIf(entry -> 
                currentTime - entry.getValue() > sendInterval * 1000L);
            
            log.debug("清理过期数据完成，当前存储验证码数量: {}", codeStorage.size());
        } catch (Exception e) {
            log.error("清理过期数据失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 发送验证码
     * @param phoneNumber 手机号
     * @return 是否发送成功
     */
    public boolean sendVerificationCode(String phoneNumber) {
        // 检查发送间隔
        Long lastSendTime = sendTimeStorage.get(phoneNumber);
        if (lastSendTime != null) {
            long timeSinceLastSend = System.currentTimeMillis() - lastSendTime;
            if (timeSinceLastSend < sendInterval * 1000L) {
                log.warn("手机号 {} 发送验证码过于频繁，距离上次发送 {} 秒", 
                    phoneNumber, timeSinceLastSend / 1000);
                return false;
            }
        }
        
        // 生成验证码
        String code = generateCode();
        log.info("为手机号 {} 生成验证码: {}", phoneNumber, code);
        
        // 发送短信
        boolean sendResult = smsService.sendVerificationCode(phoneNumber, code);
        if (!sendResult) {
            log.error("手机号 {} 验证码发送失败", phoneNumber);
            return false;
        }
        
        // 构建短信内容（与发送的内容保持一致）
        String content = String.format("【中医学习助手】您的验证码是%s，该验证码5分钟内有效，请勿泄漏于他人！", code);
        
        // 存储短信内容到内存
        VerificationCodeInfo codeInfo = new VerificationCodeInfo(content);
        codeStorage.put(phoneNumber, codeInfo);
        
        // 记录发送时间
        sendTimeStorage.put(phoneNumber, System.currentTimeMillis());
        
        log.info("手机号 {} 验证码发送成功，短信内容已存储到内存", phoneNumber);
        return true;
    }
    
    /**
     * 验证验证码
     * @param phoneNumber 手机号
     * @param code 验证码
     * @return 是否验证成功
     */
    public boolean verifyCode(String phoneNumber, String code) {
        VerificationCodeInfo codeInfo = codeStorage.get(phoneNumber);
        
        if (codeInfo == null) {
            log.warn("手机号 {} 验证码已过期或不存在", phoneNumber);
            return false;
        }
        
        // 检查是否过期
        if (codeInfo.isExpired(expireTime)) {
            log.warn("手机号 {} 验证码已过期", phoneNumber);
            codeStorage.remove(phoneNumber);
            return false;
        }
        
        // 从存储的短信内容中提取验证码
        String storedCode = extractCodeFromContent(codeInfo.getContent());
        
        if (storedCode == null) {
            log.error("手机号 {} 无法从短信内容中提取验证码", phoneNumber);
            return false;
        }
        
        boolean isValid = storedCode.equals(code);
        if (isValid) {
            // 验证成功后删除验证码信息
            codeStorage.remove(phoneNumber);
            log.info("手机号 {} 验证码验证成功", phoneNumber);
        } else {
            log.warn("手机号 {} 验证码验证失败，输入: {}, 存储: {}", phoneNumber, code, storedCode);
        }
        
        return isValid;
    }
    
    /**
     * 检查是否可以发送验证码
     * @param phoneNumber 手机号
     * @return 是否可以发送
     */
    public boolean canSendCode(String phoneNumber) {
        Long lastSendTime = sendTimeStorage.get(phoneNumber);
        if (lastSendTime == null) {
            return true;
        }
        
        long timeSinceLastSend = System.currentTimeMillis() - lastSendTime;
        return timeSinceLastSend >= sendInterval * 1000L;
    }
    
    /**
     * 销毁方法，清理资源
     */
    public void destroy() {
        if (scheduler != null && !scheduler.isShutdown()) {
            scheduler.shutdown();
            try {
                if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                scheduler.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
}
